/*
 * Object.cpp
 *
 *  Created on: Aug 5, 2013
 *      Author: alexandru
 */

#include "Object.h"

namespace stn {

//TO DO de implementat metoad pentru {}


int Object::MODE_STRING=1;
int Object::MODE_NUM=2;
int Object::MODE_BOOL=3;
int Object::MODE_OBJ=4;
int Object::MODE_ARR=5;


//constructors:

Object::Object() {
	prefix="";
}

Object::~Object() {
//    using namespace std;
//    cout << "object " << getName() << " is destroyed" << endl;
	//delete commandResponse; //sterge pointeri numai daca el e pointer
}


//1 String
Object::Object(const char * ppropName, const char * pValue){

			prefix="";
			propName=ppropName;
			NumberType=0;
			BooleanType=false;
			PROP_TYPE=1;
			StringType=pValue;
}

//2 Number as double
Object::Object(const char * ppropName, double pdNumber){
			propName=ppropName;
			NumberType=pdNumber;
			BooleanType=false;
			PROP_TYPE=2;
			prefix="";
}


//2 Number as int
Object::Object(const char * ppropName, int pdNumber){
			propName=ppropName;
			NumberType=pdNumber;
			BooleanType=false;
			PROP_TYPE=2;
			prefix="";
	}

//3 Bolean
Object::Object(const char * ppropName, bool pbolValue){
					propName=ppropName;
					BooleanType=pbolValue;
					NumberType=0;
					PROP_TYPE=3;
					prefix="";
			};

//5 object
Object::Object(const char * ppropName){
	prefix="";
	std::string str(ppropName);

		if(str[0]=='"' && str[str.length()-1]=='"'){

					tstr=str.substr(1, str.length()-2);
					propName=tstr.c_str();
		}else{
			propName=ppropName;
		}
			NumberType=0;
			BooleanType=false;
			PROP_TYPE=4;
}

//6 obiect cu comanda
Object::Object(const char * ppropName, std::string strVal){
	using namespace std;
		prefix="";
		std::string str(ppropName);


		bool ContainsNotBlank1=(str.find_first_not_of("\t\n ")==string::npos);
		    bool ContainsNotBlank2=(str.find_first_not_of("\t\n ")==string::npos);
		    bool ContainsNotBlank3=(str.find_first_not_of("\t\n u")==string::npos);
//		    cout << ContainsNotBlank1 <<endl;
//		    cout << ContainsNotBlank2 <<endl;
//		    cout << ContainsNotBlank3 <<endl;
if(ContainsNotBlank1 || ContainsNotBlank2 || ContainsNotBlank3){
	 cout << "ERROR " <<endl;
	std::exit(0);
}


		if(str[0]=='\"' && str[str.length()-1]=='\"'){

					tstr=str.substr(1, str.length()-2);
					propName=tstr.c_str();
		}else{
			propName=ppropName;
		}
		StringType="";
		//std::cout << "STR VAL= "<< strVal << std::endl;
		//std::cout << "STR NAME= "<< ppropName << std::endl;
		setValue(strVal);


}



//7 Obiect tip eroare

Object::Object(Error * eroare){

	Object timestamp("timestamp", Utils::currentDateTime());
	Object one("severity", eroare->getGravity().c_str());
	Object two("message", eroare->getMessage().c_str());
	Object three("statusCode", eroare->getStatusCode());

	PROP_TYPE=Object::MODE_OBJ;
	setName(ERROR_OBJECT_NAME);
//	push(new Object("timestamp", Utils::currentDateTime()));
//	push(new Object("severity", eroare->getGravity().c_str());
	addObject(timestamp);
	addObject(one);
	addObject(two);
	addObject(three);

	delete eroare;

}


//8 Obiect din structura xml

Object::Object(XmlStruct * xmlStruct){
	using namespace std;
	PROP_TYPE=Object::MODE_OBJ;


	setName(xmlStruct->nodeName);

	if(xmlStruct->innerContent!=UTILS_STR_NULL){
			setValue(xmlStruct->innerContent);
		}


	if(xmlStruct->xmlAttributes.size()>0){
		Object * xmlAttr = new Object(UTILS_DEFAULT_XMLATTR_NAME);
		for(unsigned int i=0; i<  xmlStruct->xmlAttributes.size(); i++){
				Object * xmlAttrProp = new Object(Utils::safetizeComma(xmlStruct->xmlAttributes.at(i).property).c_str(), Utils::safetizeComma(xmlStruct->xmlAttributes.at(i).value));
				xmlAttr->push(xmlAttrProp);
			}
		push(xmlAttr);

		if(xmlStruct->innerContent!=UTILS_STR_NULL){ // daca are nodeValue
			Object * xmlValue=new Object(UTILS_DEFAULT_XMLNODE_NAME, Utils::safetizeComma(xmlStruct->innerContent));
			push(xmlValue);
		}

	}
	delete xmlStruct;
//	delete
}




//setters and getters and utils:

void Object::setType(int mode){
	PROP_TYPE=mode;
}

int Object::getType(){
	return PROP_TYPE;
}


void Object::setName(std::string str){

	boost::algorithm::trim(str);

	//std::cout << "SET NAME |" << str << "|" << std::endl;
		if(str.at(0)=='"' && str.at(str.length()-1)=='"'){
			tstr=str.substr(1, str.length()-2);
			propName=tstr.c_str();
		}else{
			propName=str.c_str();
		}

	}

std::string Object::getName(){
		return propName;
	}




inline bool Object::IsNumber(char c){
	return ((c >= '0' && c <= '9') || c == '.' || c == '-');
}



//IMPORATNT METHODS:


const char * Object::toJsonBeauty(std::string strPre){
	using namespace std;
	result.clear();
	string suffix="\n";
	int pre=0;

	if(!isRoot){
		pre = (int) getName().length()+5;
	}



	for(int i=0; i<pre; i++){
		strPre.append("$");
	}

//	cout << "STRPRE+" << strPre << endl;
//	cout << "getNAme+" << getName() << endl;
//	cout << "lung+" << getName().length() << endl;
//	cout << "pre+" << pre << endl;

	switch(PROP_TYPE){
			case 1:
				if(isRoot) result+=prefix+"{";
	            result+='\"';
				result+=propName;
				result+="\":";
				result+="\"";
				result+=StringType;
				result+="\"";
				if(isRoot) result+="}";
				break;

			case 2:
				if(isRoot) result+=UTILS_ACOLSTART;
				result+="\"";
				result+=propName;
				result+="\":";
				result+=Utils::dts(NumberType);
				if(isRoot) result+=UTILS_ACOLEND;
			break;

			case 3:
				if(isRoot) result+=UTILS_ACOLSTART;
				result+="\"";
				result+=propName;
				result+="\":";
				if(BooleanType) result+="true";  else result+="false";
				if(isRoot) result+=UTILS_ACOLEND;
			break;

			case 4:

				if(!isRoot){
					result+=strPre;
					result+="\"";
					result+=propName;
					result+="\":";
				}
					result+=UTILS_ACOLSTART+suffix;

					if(objectList.size()>0){
						for(int i=0; i<(int)objectList.size()-1; i++){
												objectList.at(i).isRoot=false;
												result+=strPre+objectList.at(i).toJsonBeauty(strPre);
												result+=","+suffix;
										}
						objectList.at(objectList.size()-1).isRoot=false;
						result+=strPre+objectList.at(objectList.size()-1).toJsonBeauty(strPre);
						result+=suffix;
					}

					result+=strPre+UTILS_ACOLEND;
					result+=suffix;
				break;

				case 5:
						if(!isRoot){
										result+="\"";
										result+=propName;
										result+="\":";
									}
										result+='[';
										if(objectList.size()>0){
											for(int i=0; i<(int)objectList.size()-1; i++){
													objectList.at(i).isRoot=true;
													result+=objectList.at(i).getJsonValue();
													result+=",";
											}
											objectList.at(objectList.size()-1).isRoot=true;
											result+=objectList.at(objectList.size()-1).getJsonValue();
										}
										result+=']';
						break;
			}
			return result.c_str();
}//exit toJsonBeauty

const char * Object::toXMLBeauty(){

	return "unimplemented";
}


//TODO toXML method
std::string Object::toXML(){
	result.clear();

	return "";
}


std::string  Object::toJson(){
using namespace std;
		result.clear();
//		suffix='\n';
		//std::cout << getName() << "  has "<< objectList.size() << " objects "<< std::endl;

		//cout << "TO JSON type" << PROP_TYPE << endl;
		switch(PROP_TYPE){
		case 1:
			if(isRoot) result+="{";
            result+="\"";
			result+=propName;
			result+="\":";

			result+="\"";
			result+=StringType;
			result+="\"";
			if(isRoot) result+="}";
			break;

		case 2:
			if(isRoot) result+=UTILS_ACOLSTART;
			result+="\"";
			result+=propName;
			result+="\":";

			result+=Utils::dts(NumberType);
			if(isRoot) result+=UTILS_ACOLEND;
		break;


		case 3:
			if(isRoot) result+=UTILS_ACOLSTART;
			result+="\"";
			result+=propName;
			result+="\":";

//			result+="\"";
			if(BooleanType) result+="true";  else result+="false";
			if(isRoot) result+=UTILS_ACOLEND;
			break;


		case 4:


			if(!isRoot){
				result+="\"";
				result+=propName;
				result+="\":";
			}


				result+=UTILS_ACOLSTART;

				if(objectList.size()>0){
					for(int i=0; i<(int)objectList.size()-1; i++){
											objectList.at(i).isRoot=false;
											result+=objectList.at(i).toJson();
											result+=",";
									}
					objectList.at(objectList.size()-1).isRoot=false;
					result+=objectList.at(objectList.size()-1).toJson();
				}


				result+=UTILS_ACOLEND;

			break;

			case 5:

					if(!isRoot){
									result+="\"";
									result+=propName;
									result+="\":";
								}


									result+='[';

									if(objectList.size()>0){
										for(int i=0; i<(int)objectList.size()-1; i++){
												objectList.at(i).isRoot=true;
												result+=objectList.at(i).getJsonValue();
												result+=",";
										}
										objectList.at(objectList.size()-1).isRoot=true;
										result+=objectList.at(objectList.size()-1).getJsonValue();
									}

									result+=']';

					break;
		}




		return result;
	}




void Object::addObject(Object object){
		if(PROP_TYPE < Object::MODE_OBJ){
			PROP_TYPE=Object::MODE_OBJ;
		}
		objectList.push_back(object);
	}


void Object::push(Object *object){
		if(PROP_TYPE < Object::MODE_OBJ){
					PROP_TYPE=Object::MODE_OBJ;
				}
			objectList.push_back(*object);
		}


Object Object::getByIndex(std::string index){
		ind=atoi(index.c_str());
		if(ind<(int)objectList.size()){
			return objectList.at(ind);
		}
		return Object(new Error(Error::COMMAND_FAILED, ERROR_INDEX_OUT_OF_RANGE+index, ErrorStatusCodes::range_error_index_out_of_range ));
	}

Object * Object::getInstanceByIndex(std::string index){
		ind=atoi(index.c_str());

		if(ind<(int) objectList.size()){
			return &objectList.at(ind);
		}
		return new Object(new Error(Error::COMMAND_FAILED, ERROR_INDEX_OUT_OF_RANGE+index, ErrorStatusCodes::range_error_index_out_of_range ));
	}

Object Object::getByName(std::string objPropName){
		for(int i=0; i<(int)objectList.size(); i++){
								if(objectList.at(i).getName()==objPropName){
									return objectList.at(i);
								}
						};

		return Object(new Error(Error::COMMAND_FAILED, ERROR_NAME_OUT_OF_RANGE+objPropName, ErrorStatusCodes::range_error_name_out_of_range ));
	}


void Object::removeAtIndex(int index){
	objectList.erase(objectList.begin()+index);
}

void Object::removeAtIndex(std::string index){
	boost::algorithm::trim(index);
	ind=atoi(index.c_str());
	std::cout << "REMOVE AT INDEX" << ind << std::endl;
	if(ind<(int)objectList.size()){
		objectList.erase(objectList.begin()+ind);
	}else{
		std::cout << "REMOVE FAILED" << std::endl;
	}

}

Object * Object::getInstanceByName(std:: string objPropName, bool loose){
	for(int i=0; i<(int)objectList.size(); i++){
									if(objectList.at(i).getName()==objPropName){
										return &objectList.at(i);
									}
							};

	if(loose){
		std::cout << "CREEZ OBIECTUL " << objPropName << std::endl;
		//Object * tmp= new Object(objPropName.c_str());
		Object tmp(objPropName.c_str());
		objectList.push_back(tmp);
		return getInstanceByName(objPropName, false);
	}

	return new Object(new Error(Error::COMMAND_FAILED, ERROR_NAME_OUT_OF_RANGE+objPropName, ErrorStatusCodes::range_error_name_out_of_range ));
}


const char * Object::getJsonValue(){

	result.clear();
            switch(PROP_TYPE){
                case 1:
                	result+="\"";
                	result+=StringType;
                	result+="\"";
                    break;
                case 2:
                	result+=Utils::dts(NumberType).c_str();
                   break;
                case 3:
                   if(BooleanType) result+="true"; else result+="false";
                   break;
                default:
                	isRoot=true;
                  return toJson().c_str();
            }
            isRoot=true;
		return result.c_str();
	}


std::string Object::getStringValue(){
	result.clear();
	            switch(PROP_TYPE){
	                case 1:
	                	result=StringType;
	                    break;
	                case 2:
	                	result=Utils::dts(NumberType);
	                   break;
	                case 3:
	                   if(BooleanType) result="true"; else result="false";
	                   break;
	                default:
	                  return toJson();
	            }
			return result;
}




void Object::setValue(std::string str){
using namespace std;


if(str.length()<=0){
	puts("FUCK OFF!!");
	return;
}

cout << " erase data" << endl;

objectList.erase (objectList.begin(),objectList.end());
objectList.clear();

boost::algorithm::trim(str);


		cout << "object named |"<< propName << "| set value --|" << str << "|--" <<std::endl;

//		  std::size_t b_first = str.find("{");
//		  std::size_t b_last = str.find_last_of("}");
//
//		  std::size_t a_first = str.find("[");
//		  std::size_t a_last = str.find_last_of("]");
//
//
//		  std::size_t g_first = str.find("\"");
//		  std::size_t g_last = str.find_last_of("\"");
		  //std::size_t g_last = str.find("\"", g_first+1);

		char first=str.at(0);
		char last = *str.rbegin();


//		  cout << "B{" << endl;
//		  cout << b_first << endl;
//
//
//		  cout << "A[" << endl;
//		  		  cout << a_first << endl;
//
//
//		  cout << "G\"" << endl;
//		  cout << g_first << endl;


		std::string res;


		//daca are format xml cu <>

		if(first==UTILS_CHAR_SMALLER && last==UTILS_CHAR_BIGGER){
			parseXML(str);

			return;
		}


		//daca are format ()
						if(first=='(' && last==')'){



							string tmp=str.substr(1, str.length()-2);
//							boost::algorithm::trim(tmp);
							std::size_t delimiter = tmp.find(":");



							if(tmp.length()>2){
								if(tmp.at(0)==UTILS_SHARP_KEY && tmp.at(1)==UTILS_SHARP_KEY){
									runCommand(tmp);
									return;
								}
							}

							string name=tmp.substr(0, delimiter);


							//cout << b_first << " -- " << b_last << " -- " << str.length()-1 << endl;
							res=tmp.substr(delimiter+1, tmp.length()-1);
//							boost::algorithm::trim(name);
//							boost::algorithm::trim(res);
//							cout << "tmp="<< tmp << "   l:"<< tmp.length()<< endl;
//							cout << "RES="<< res << "   l:"<< res.length()<< endl;
//							cout << "NAM="<< name << "   l:"<< name.length()<< endl;
							//cout << "this is object_______" << endl;

							setName(name);





							setValue(res);
//							cout << "CHENGE THIS OBJECT " << endl;
//							cout << toJson() << endl;

							return;

						}

		//daca are format {}
				if(first=='{' && last=='}'){
					//cout << b_first << " -- " << b_last << " -- " << str.length()-1 << endl;
					res=str.substr(1, str.length()-2);
					//cout << "this is object_______" << endl;
					PROP_TYPE=Object::MODE_OBJ;
					convertObject(res);
					return;

				}

				//daca are format []
			if(first=='[' && last==']'){
					//cout << a_first << " -- " << a_last << " -- " << str.length()-1 << endl;
					res=str.substr(1, str.length()-2);
					//cout << "this is array" << endl;
					PROP_TYPE=Object::MODE_ARR;
					convertArray(res);
					return;

			}


			//daca are format " " //TODO de escapat ghilimelele din string si aici
		if(first=='"' && last=='"'){
						res=str.substr(1, str.length()-2);
						//cout << "this is string with value|"<< res << endl;
						PROP_TYPE=Object::MODE_STRING;
						boost::replace_all(res, "\"", "\\\"");
						StringType=res;
						return;
		}





			//daca e true
			if(str=="true"){
				//cout << "this is bool true" << endl;
				PROP_TYPE=Object::MODE_BOOL;
				BooleanType=true;
				return;
			}


			//daca e false
			if(str=="false"){
				//cout << "this is bool false" << endl;
				PROP_TYPE=Object::MODE_BOOL;
				BooleanType=false;
				return;
			}


			bool maybeNumber=true;

			for (unsigned i=0; i<str.length(); ++i){
				c=str.at(i);
				if(!IsNumber(c)){
					maybeNumber=false;
				}
			}

			if(maybeNumber){
				//cout << "this is number" << endl;
				PROP_TYPE=Object::MODE_NUM;
				NumberType=atof(str.c_str());
				return;
			}


			//TODO de escapat ghilimelele din string
			cout << "SETEZ DEFAULT "<< str << " STRING IN" << getName()  << endl;
			PROP_TYPE=Object::MODE_STRING;
			//boost::replace_all(target, "I hope t", "T");
			boost::replace_all(res, "\"", "\\\"");
			StringType=str;
			cout << "SETEZ DEFAULT "<< StringType << " STRING IN" << getName()  << endl;
	}




void Object::convertObject(std::string str){


using namespace std;
	nrAcol=0;
	nrPaDr=0;
	iPr=true;
	skip=false;
	propNamT.clear();
	propValT.clear();
	listaTemp.clear();
	PROP_TYPE=4;


	int numQ=0;


	//cout << "make object from string |" << str<< "|" << endl;
		for (unsigned i=0; i<str.length(); ++i){

				c=str.at(i);
				//cout << c << endl;
				switch(c){
					case '{':
						nrAcol++; skip=false;
					break;

					case '}':
						nrAcol--; skip=false;
					break;

					case '[':
						nrPaDr++; skip=false;
					break;

					case ']':
						nrPaDr--; skip=false;
					break;

					case '"':
						numQ++;
						skip=false;
					break;


					case '\n':
					case '\t':
					case '\r':
					case '\f':
						skip=true;
					break;


					case ' ':
						if(iPr && numQ%2==0){
							skip=true;
						}
					break;


					case ',':
						if(nrAcol==0 && nrPaDr==0 && numQ%2==0){



							//cout << "___"<< numQ << "___obiect_____acolade{}: "<< nrAcol<< "_____VIRGULA_______|"<< propNamT << "| si prop |"  << propValT<< "|" << endl;
							Object obj(propNamT.c_str(), propValT);
							addObject(obj);
							propNamT.clear();
							propValT.clear();
							skip=true;
							iPr=true;
						}
					break;

					case ':':

						if(nrAcol==0 && nrPaDr==0){
							iPr=false;
							skip=true;

						}

						//cout << propNamT << endl;
					break;

					default:
						skip=false;

					break;
				}//exit switch

				//cout << numQ << endl;


				if(skip==false){
					if(iPr){
						propNamT+=c;
					}else{
							propValT+=c;
					}
				}

				//adding the lastOne:
				if(i==str.length()-1){
					tempObject tmp;
					tmp.name=propNamT;
					tmp.prop=propValT;
					listaTemp.push_back(tmp);
				}



		}//exit for

		//cout << "_______________final_ obiect___PROP_|"<< propNamT << "| si val =|"  << propValT<< "|" << endl;
		Object obj(propNamT.c_str(), propValT);
		addObject(obj);

		//cout << "--->" << toJson()  << endl;

	}//exit convert object





void Object::convertArray(std::string str){
	using namespace std;


			nrAcol=0;
			nrPaDr=0;
			PROP_TYPE=5;
			skip=false;
			propNamT.clear();
			propValT.clear();
			listaTemp.clear();
			int numQ=0;


			for (unsigned i=0; i<str.length(); ++i){


							c=str.at(i);

							switch(c){
								case '{':
									nrAcol++; skip=false;
								break;

								case '}':
									nrAcol--; skip=false;
								break;

								case '[':
									nrPaDr++; skip=false;
								break;

								case ']':
									nrPaDr--; skip=false;
								break;


								case ' ':
									if(iPr && numQ%2==0){
										skip=true;
									}
								break;

								case '\"':
									numQ++;
									skip=false;
								break;


								case '\n':
								case '\t':
								case '\r':
								case '\f':
									skip=true;
								break;


								case ',':
									if(nrAcol==0 && nrPaDr==0 && numQ%2==0){
										skip=true;
										Object obj("AO", propValT);
										addObject(obj);
										//cout << "VIRGULA< ADAUAG" << propValT << endl;
										propValT.clear();
									}
								break;

								default:
									skip=false;
								break;
							}//exit switch




						if(skip==false){
							propValT+=c;
						}



			}//exit for


			if(propValT.length()>0 || Utils::isAllEmpty(propValT)==false){
				//cout << "final arr cu val" << propValT << endl;
				Object obj("AO", propValT);
				addObject(obj);
			}else{
				Object obj("AO");
				addObject(obj);
				//cout << "EMPTY ARRAY" << endl;
			}



						//cout << listaTemp.at(i).name << " : " << listaTemp.at(i).prop << endl;



		}//exit convert array



std::string Object::runCommand(std::string input){
	using namespace std;
	boost::algorithm::trim(input);
	cout << "scanning  "<< input << " in object "<< getName() << endl;



	if(input.length()<0){
				return "fuck you! You typed nothing!"; //TODO ER
			}


	try {
	    if (boost::starts_with(input, FUNC_SET_NAME)){

	    	if(input.at(input.length()-1)==')'){
	    		int a=input.length();
	    		string foo_value = input.substr(0, a-1);
				foo_value = foo_value.substr(strlen(FUNC_SET_NAME), ind);
				cout << "set name : " << foo_value << endl;
				setName(foo_value);
				return "NAME CHANGED";
	    	}
	    }
	} catch (boost::bad_lexical_cast ex) {
	    // bad parameter

	}

	if(input.length()>1){



		if(input.at(0)==UTILS_SHARP_KEY && input.at(1)==UTILS_SHARP_KEY){
				std::string command;
				std::string rest;

				for (unsigned i=2; i<input.length(); ++i){
					command+=input.at(i);
					cout << command << endl;
					if(command==Query::COMMMAND_LOAD_DB){
						goto loadDbLabel;
					}

					if(command==Query::COMMMAND_IMPORT_FOLDER_STRUCT){
						goto importFolderStruct;
					}
				}


				loadDbLabel:
						rest=input.substr(Query::COMMMAND_LOAD_DB.length()+2, input.length());
						boost::algorithm::trim(rest);
						cout << "REST: " << rest << endl;
						loadDb(rest);
						return "DATABASE "+rest+" LOADED";

				importFolderStruct:
						rest=input.substr(Query::COMMMAND_IMPORT_FOLDER_STRUCT.length()+2, input.length());
						boost::algorithm::trim(rest);
						cout << "REST: " << rest << endl;
						importFolderStruct(rest);
						return "FILE "+rest+" IMPORTED";

				//TODO rest of ##commands


				return "outputcommand here";
			}
	}


	if(input==FUNC_TO_JSON){
		isRoot=true;
		return toJson();
	}

	if(input==FUNC_GET_JSON_VALUE){
			return getJsonValue();
		}

	if(input==FUNC_EXIT){
				return "response db closed";
			}

	if(input==FUNC_GET_NAME){
				return getName();
			}

	if(input==FUNC_SAVE){
				saveToFile();
				return "response db saved";
			}

//	if(input=="SAVE"){
//		return "SAVE TO FILE";
//	}




	bool isDin=false;



	string prop;
	string indexName;
	string restToScan;


	prop.clear();
	indexName.clear();
	restToScan.clear();


	Object * pushable;
        string query;
        bool queryOn=false;
        
	for (unsigned i=0; i<input.length(); ++i)
					  {
						char c=input.at(i);



						switch(c){
							case '.':
								restToScan=input.substr(prop.length()+1, input.length());
								goto returnAsObject;
							break;


							case ' ':
							case '\n':
							case '\t':
							case '\r':
							case '\f':

								if(queryOn) query+=c;
								break;

							case UTILS_CHAR_SMALLER:
									cout << "prop.length()="<< prop.length() << " " << prop<< endl;

									if(prop.length()>0){
										restToScan=input.substr(prop.length(), input.length());
										goto returnAsObject;
									}else{
										queryOn=true;
									}
									//cout << "prop.length()="<< prop.length() << " " << prop<< endl;
							break;

							case UTILS_CHAR_BIGGER:
								// restToScan=input.substr(query.length(), input.length());
								queryOn=false;
								goto runQuery;
							break;



							case '-':
								cout << "-prop.length()="<< prop.length() << " " << prop<< endl;
								if(prop.length()>0){
									restToScan=input.substr(prop.length()+1, input.length());
									goto removeInObject;
								}else{
									std::size_t eqFind = input.find("-");
									boost::algorithm::trim(restToScan);
									restToScan=input.substr(eqFind+1, input.length());
									goto removeInThis;
								}
								break;

							case '+':

									cout << "+prop.length()="<< prop.length() << " " << prop<< endl;

									if(prop.length()>0){
										restToScan=input.substr(prop.length()+1, input.length());
										goto pushValueInObject;
									}else{
										std::size_t eqFind = input.find("+");
										boost::algorithm::trim(restToScan);

										restToScan=input.substr(eqFind+1, input.length());
										goto pushValuesInThis;
									}
								break;


							case '=':
								cout << "=prop.length()="<< prop.length() << " " << prop<< endl;

								if(prop.length()>0){
									restToScan=input.substr(prop.length()+1, input.length());
									goto setValueInObject;
								}else{
									std::size_t eqFind = input.find("=");
									boost::algorithm::trim(restToScan);
									boost::algorithm::trim_left(restToScan);
									restToScan=input.substr(eqFind+1, input.length());
									//restToScan=Utils::trim(restToScan);

									goto setValueInThis;
								}

							break;


							case '[':
								if(prop.length()>0){
									restToScan=input.substr(prop.length()+1, input.length());
									goto returnAsObject;
								}
								isDin=true;
								break;

							case ']':

								if(isDin){
									restToScan=input.substr(indexName.length()+2, input.length());
									goto returnAsArrayItem;
								}else{
									indexName=prop;
									restToScan=input.substr(prop.length()+1, input.length());
									goto returnAsArrayItem;
								}

							break;

							default:
								if(isDin && !queryOn){
									indexName+=c;
								}else if(!isDin&&!queryOn){
									prop+=c;
								}else{
									query+=c;
								}
							break;
						}


					  }//exit for


//		cout << "SETTED PROP: " << prop << endl;

		returnAsObject:
					cout << "RETRUN AS OBJECT " << prop << endl;
					cout << "input.length()=" << input.length()<< " "<< input << endl;
					cout << "prop.length()="<< prop.length() << " " << prop<< endl;
					cout << "restToScan.length()=" << restToScan.length()<< " "<< restToScan << endl;

			if(restToScan.length()>0){
				return  getInstanceByName(prop, false)->runCommand(restToScan);
			}else{
				commandResponse=getInstanceByName(prop, false);
				commandResponse->isRoot=true;
				return commandResponse->toJson();
			}


		returnAsArrayItem:
					cout << "RETURN AS ARRAY "<< indexName.length() << " indexName=" << indexName<< " " << endl;
					cout << "input.length()=" << input.length()<< " "<< input << endl;
					cout << "indexName.length()="<< indexName.length() << " " << indexName<< endl;
					cout << "restToScan.length()=" << restToScan.length()<< " "<< restToScan << endl;
					prop=indexName;

			if(restToScan.length()>0){
				return getInstanceByIndex(indexName)->runCommand(restToScan);
			}else{
				commandResponse=getInstanceByIndex(indexName);
				commandResponse->isRoot=true;
				return  commandResponse->toJson();
			}


		setValueInThis:
                        cout << "inThis object called "<< getName() << " restToScan.length()=" << restToScan.length()<< " "<< restToScan << endl;
                        cout << "inThis object to json "<< toJson()  << endl;
                        setValue(restToScan);
                        cout << toJson() << endl;
                        return "Value setted in "+getName();

		setValueInObject:
                        cout << "in Object SET VALUE  |" << restToScan << "|" << "IN OBJECT "<< getName()<< endl;
                        getInstanceByName(prop, true)->setValue(restToScan);
                        return "Value setted in "+prop;

		pushValueInObject:
			cout << "restToScan.length()=" << restToScan.length()<< " "<< restToScan << endl;
			pushable=new Object("AO", restToScan);
			getInstanceByName(prop, true)->push(pushable);
			return "element pushed in "+prop;


		pushValuesInThis:
			pushable=new Object("AO", restToScan);
			push(pushable);
			return "element pushed in "+getName();


		removeInObject:
                        getInstanceByName(prop, false)->removeAtIndex(restToScan);
                        return "more to do removed from "+prop+" at index "+restToScan;

		removeInThis:
                        removeAtIndex(restToScan);
                        return "removed from "+getName()+" at index "+restToScan;
                        
		runQuery:
       	   	   	   	   cout << "RUN QUERY " << query << endl;
       	   	   	   	   boost::algorithm::trim(query);
       	   	   	   	   if(query.length()>4){
						   restToScan=input.substr(query.length()+2, input.length());
						   cout << "rest to scan " << restToScan << endl;
						   if(restToScan.length()>0){
								return runQuery(query)->runCommand(restToScan);
							}else{
								return  runQuery(query)->getJsonValue();
						}
       	   	   	   	   }

       	   	   	   	   return "RUN QUERY "+query;




	return "Syntax error";
}



Object::range Object::toRange(std::string arg){
	using namespace std;
	range ret;
if(arg.find('-') != std::string::npos){
	vector<string> strs;
	boost::split(strs,arg,boost::is_any_of("-"));

	if((int)strs.size()>2){
		Error * err= new Error(Error::SINTAX_ERROR, "undefined token - in second query keyword "+arg, ErrorStatusCodes::syntax_error_query_in_range);
		delete err;
		ret.min=0;
		ret.max=(int) objectList.size();
	}else{
		ret.min=atoi(strs.at(0).c_str());
		if(strs.at(1)==Query::KEYWORD_ALL){
			ret.max=(int) objectList.size();
		}else{
			ret.max=atoi(strs.at(1).c_str());
		}

		if(ret.min<0){
			Error * err= new Error(Error::RANGE_ERROR, "first range invalid in second query keyword "+arg, ErrorStatusCodes::range_error_query_in_range_firstarg);
			delete err;
			ret.min=0;
		}
		if(ret.max>(int) objectList.size()-1){
			Error * err= new Error(Error::RANGE_ERROR, "second range invalid in second query keyword "+arg, ErrorStatusCodes::range_error_query_in_range_secondarg);
			delete err;
			ret.max=(int) objectList.size();
		}
	}
}else{
	ret.min=0;
	ret.max=(int) objectList.size();
}
	return ret;
}




Object::RealVal Object::getRealValue(){
	RealVal realValue;
	realValue.numeric=NumberType;
	realValue.boolean=BooleanType;

	switch(PROP_TYPE){
	case 4:
	case 5:
		realValue.charList=toJson();
		break;
	default:
		realValue.charList=StringType;
		break;
	}

return realValue;
}


bool Object::compareNumeric(int one, int two, std::string command){
	if(command==Query::COMP_LESSTHAN){
		return one<two;
	}

	if(command==Query::COMP_MORETHAN){
			return one>two;
		}

	if(command==Query::COMP_EQ){
				return one==two;
			}
	if(command==Query::COMP_NOTEQ){
					return one!=two;
				}


	//TODO throw syntax error
	return false;
}

/**
 * ce am convertiti
 * ce a scris userul
 * termenul de comparatie
 */
bool Object::compareStrings(std::string pov, std::string input, std::string command){

	bool temp=Utils::isLikeWildcard(pov, input);
	if(command==Query::COMP_LIKE){
		return temp;
	}

	if(command==Query::COMP_NOTLIKE){
		return !temp;
	}

	return temp;
}



Object * Object::useValuesNumeric(std::string value, std::string action, std::string comparison, std::string updateValue){
	using namespace std;
	int val=atoi(value.c_str());//TODO some other atoi?

	Object * response=new Object(Query::RESPONSE, 0);
	Object currentObject;
	modified=0;
	deleted=0;


	for (vector<Object>::iterator it=objectList.begin(); it!=objectList.end(); it++){
		if(it->getType()==Object::MODE_NUM){
			int cval=it->getRealValue().numeric;
			cout <<  it->getName()<<"  "<< cval << "<" << val << endl;
			if(compareNumeric(cval, val, comparison)){
				numModifed++;
				if(validIs_modInRange(numModifed, between)){
					if(action== Query::OPERATOR_UPDATE){
						it->setValue(updateValue);
						modified++;
					}

					if(action== Query::OPERATOR_SELECT){
						currentObject=*(it);
						response->addObject(currentObject);
					}

					if(action== Query::OPERATOR_DELETE){
						objectList.erase(it);
						deleted++;
						it--;
					}
				}//exit skipper
			}
		}
	}

	if(modified!=0 || deleted!=0){
		delete response;
		return &(*this);
	}

	return response;
}



/**
 * dataType: PROP sau VALUE
 * comparisonterm VALOAREA DE COMPARATIE
 * comparison LIKE sau NOTLIKE
 */
Object * Object::useDataStrings(std::string dataType, std::string comparisonTerm, std::string comparison, std::string action, std::string updateValue){
	using namespace std;
	Object * response=new Object(Query::RESPONSE, 0);
	Object currentObject;
	modified=0;
	deleted=0;
cout << comparisonTerm << endl;
cout << updateValue << endl;
cout << "DATA TYPE " << dataType << "    TERMEN DE COMPARATIE: "<<comparisonTerm << "    DATA TYPE:" << getDataByType(dataType, currentObject) << endl;

	for (vector<Object>::iterator it=objectList.begin(); it!=objectList.end(); it++){
		currentObject=*(it);
		bool is=compareStrings(getDataByType(dataType, currentObject), comparisonTerm, comparison);


		cout << "is=" << is << endl;
		if(is){
			numModifed++;
			cout << numModifed << endl;
			if(validIs_modInRange(numModifed, between)){
				if(action== Query::OPERATOR_UPDATE){
					it->setValue(updateValue);
					modified++;
				}

				if(action== Query::OPERATOR_SELECT){
					cout << "dsadasdas" << endl;
					response->addObject(currentObject);
				}

				if(action== Query::OPERATOR_DELETE){
					objectList.erase(it);
					deleted++;
					it--;
				}
			}
			//response->addObject(currentObject);
		}
	}

	if(modified!=0 || deleted!=0){
	//		response->push(new Object("deleted", deleted));
	//		response->push(new Object("modified", modified));
	//		response->push(new Object("timestamp", Utils::currentDateTime()));
			delete response;
			return &(*this);
		}

	return response;
}


bool Object::validIs_Operator(std::string oper){
	return (oper==Query::OPERATOR_SELECT || oper==Query::OPERATOR_DELETE || oper==Query::OPERATOR_UPDATE);
}

bool Object::validIs_NumericComparison(std::string numComp){
	return (numComp==Query::COMP_LESSTHAN || numComp==Query::COMP_MORETHAN || numComp==Query::COMP_EQ || numComp==Query::COMP_NOTEQ);
}

bool Object::validIs_modInRange(int number, range rata){
	return (number>=rata.min && number<rata.max);
}

bool Object::validIs_type(std::string type){
	return (type==Query::TYPE_PROP || type==Query::TYPE_VALUE);
}

bool Object::validIs_StringComparison(std::string strComp){
	return (strComp==Query::COMP_LIKE || strComp==Query::COMP_NOTLIKE);
}


std::string Object::getDataByType(std::string type, Object object){
	if(type==Query::TYPE_PROP){
		return object.getName();
	}

	if(type==Query::TYPE_VALUE){
		return object.getStringValue();
	}

	return "undefined error";
}



Object * Object::runQuery(std::string query){

    using namespace std;
    using boost::is_any_of;

    if(query.length()>1){
    	return new Object("error", "FUCKK OFF ERROR, YOU TYPED NOTHING");

    }

    numModifed=-1;
    cout << "RUN QUERY:   " << query << " "<< query.length()<<  endl;
    cout << "IN:   " << getName() << endl;
    vector<string> strVec;
    boost::algorithm::split(strVec,query,is_any_of("\t "),boost::token_compress_on);

    	if(strVec.size()>0){
    		between=toRange(strVec.at(1));
        }else{
        	 between=toRange(Query::KEYWORD_ALL);
        	 return new Object("error", "FUCKK OFF ERROR, split failed");
        }





    cout << "MIN: "<< between.min <<endl;
    cout << "MAX: "<< between.max <<endl;

    if(validIs_Operator(strVec.at(0))){//daca primul termen e un operator corect

    	//daca e value cu operator de numar
    	if(strVec.at(2)==Query::TYPE_VALUE && validIs_NumericComparison(strVec.at(3))){
    			return useValuesNumeric(strVec.at(4), strVec.at(0), strVec.at(3), strVec.at(1));
    	    }
    	else if(validIs_type(strVec.at(2)) && validIs_StringComparison(strVec.at(3))){
    		cout << "PROP E BUN, comp e de string" << strVec.at(3)<<endl;
    		return useDataStrings(strVec.at(2), strVec.at(4), strVec.at(3), strVec.at(0), strVec.at(1));
    	}
    	else{
    		cout << "PROP NOT OK" << endl;//property not ok sau numeric comparison not ok
    	}

    }else{
    	cout << "EROARE " <<endl;
    	return new Object(new Error(Error::SINTAX_ERROR, ERROR_QUERY_FIRST_ARGUMENT_MISPELLED, ErrorStatusCodes::syntax_error_query_in_argument));
    }

    return new Object("null", "ERROR OBJECT TO IMPLEMENT IN FAILED QUERY");
}



void Object::parseXML(std::string input){

	using namespace std;

	boost::algorithm::trim(input);
	PROP_TYPE=Object::MODE_OBJ;

//	if(input.at(0)!='<' || input.at(input.length()-1)!='>'){
//		setValue(input);
//		return &(*this);
//	}



	bool aap=false;// allow attributes +
	int numl=0;

	string val;



	//bool isEnd=false;
	int numStart=0;
	int numEnd=0;
	int numMNodes=0;
	string outerContent;
	string attributes;
	bool isComment=false;
//	bool arts=false;//allow restToScan+
//	string restToScan;





//	cout << input << endl;

	for(int i=0; i< (int) input.length(); i++){

		//cout << input.at(i) << "  " << i << endl;

		switch(input.at(i)){





			case '<':

				if(input.at(i+1)==UTILS_BACKSLASH){
					numEnd++;
					aap=true;
				}
				else if(input.at(i+1)==UTILS_INTRG_MARK){
						isComment=true;
						outerContent.clear();
						attributes.clear();
						aap=false;
					}
				else{
					numStart++;
					aap=true;
				}
			break;

			case ' ':
				if(!isComment){
					aap=true; // allow atributes name +
					if(aap){
						attributes+=input.at(i);
					}
				}
			break;

			case '/':
				if(!isComment){
					if(input.at(i+1)=='>' || input.at(i-1)=='<'){
						aap=false;// not allow + for attributes
					}else{
						attributes+=input.at(i);
					}
				}

			break;

			case '>':
				if(isComment || input.at(i-1)=='-'){
					numEnd++;
					cout<< "END COMMENT AT" << i << "  -->"<< input.at(i)<< endl;
					cout<< "END COMMENT AT" << i << "  -->"<< input.at(i-1)<< endl;
					cout<< "END COMMENT AT" << i << "  -->"<< input.at(i-2)<< endl;
					cout<< numStart << "======" << numEnd<<  endl;
					outerContent.clear();
					attributes.clear();
					isComment=false;
					aap=true;
					numEnd--;
				}else{
					isComment=false;
					numl++;
					aap=false;// not allow + for attributes
	//				arts=true;
//					cout <<  input.at(i-1) << isEnd << endl;
					if(input.at(i-1)=='/'){
						numEnd++;
					}

					if(numEnd==numStart){
						numMNodes++;
						cout <<  "END OF NODE " << numMNodes << " :" << outerContent << endl;
						cout << "attributes: "<< attributes << endl;
						aap=true;
						numl=0;

						XmlStruct * xmlStruct= new XmlStruct();

						cout << outerContent << "IN HERE" << endl;
						xmlStruct->attributesLine=attributes;
						xmlStruct->nodeNameLine=outerContent;
						xmlStruct->describe();


						Object * xmlObi= new Object(xmlStruct);
						push(xmlObi);


						outerContent.clear();
						attributes.clear();
					}
				}







			break;

			default:
				if(aap && numl==0){
					attributes+=input.at(i);
				}



			break;

		}


		//cout<< numStart<< "=====" << numEnd <<outerContent << endl;

			if(!Utils::isSkippable(input.at(i)) && numEnd!=numStart){ //daca e gol sau nu e ultimul caracter din nod
				outerContent+=input.at(i);
			}




	}



}



//TODO de externalizat
void Object ::loadFromFile(){
	using namespace std;
	std::string outName="/Applications/XAMPP/xamppfiles/htdocs/jquery-jsonview-master/"+getName()+".json";
	 std::ifstream o;
	 std::string line;
	 string res;
	 o.open(outName.c_str(), ios::in);
	 if (o.is_open()) {
		 while ( getline(o, line) ){

			 res+=line;
		 }
	 }
	 o.close();

	 setValue(res);
}



void Object::setWorkingDir(std::string dirName){
	workingDir=dirName;
	std::cout << "set working dir into " << workingDir << std::endl;
}

//TODO de externalizat
void Object::saveToFile(){

	std::string outName=workingDir+getName()+DB_EXTENSION;
//	std::string outName=getName()+".json";
	 std::ofstream o(outName.c_str());

	 o << toJson() << std::endl;

	 o.close();
}




void Object::loadDb(std::string dbName){
	std::string outName=workingDir+dbName+DB_EXTENSION;
	std::ifstream o;
		 std::string line;
		 std::string res;
		 o.open(outName.c_str(), std::ios::in);
		 if (o.is_open()) {
			 while ( getline(o, line) ){
				 res+=line;
			 }
		 }
		 o.close();

		 setName(dbName);
		 setValue(res);

}



void Object::importFolderStruct(std::string pathStr){
	//necesita -lboost_system, -lboost_filesystem
using namespace boost::filesystem;
using namespace std;

	 path p (pathStr);
	 std::string caleAbsoluta;
	 std::string numeFisier;
	 Object * current;

	 try{
	 if (exists(p))    // does p actually exist?
	   {
		 caleAbsoluta=boost::filesystem::canonical(p).string();
		 numeFisier=boost::filesystem::canonical(p).stem().string();
		 numeFisier=Utils::secureFileName(numeFisier);
		 cout << "CALE ABSOLUTA" << caleAbsoluta << '\n';
		 cout << "NUME FISER" << numeFisier << '\n';

	     if (is_regular_file(p)){
	       cout << p << " file size is " << (int) file_size(p) << '\n';

	       current=new Object(numeFisier.c_str(), caleAbsoluta.c_str());
	       push(current);
		  cout << "file: " << caleAbsoluta << '\n';
		  //current=new Object(numeCurent.c_str())
	     }

	     else if (is_directory(p)){
	    	 cout << p << " is a directory containing:\n";
	    	 current=new Object(numeFisier.c_str(), caleAbsoluta.c_str());


	    	 typedef vector<path> vec;             // store paths,
			 vec v;                                // so we can sort them later
			 copy(directory_iterator(p), directory_iterator(), back_inserter(v));
			 sort(v.begin(), v.end());
			for (vec::const_iterator it (v.begin()); it != v.end(); ++it)
					{
					std::string caleAbsolutaC=boost::filesystem::canonical(*it).string();
					current->importFolderStruct(caleAbsolutaC);
					}
			 push(current);
	     }

	     else{
	       cout << p << "exists, but is neither a regular file nor a directory\n";
	     }
	   }
	   else{
	     cout << p << "does not exist\n";
	   }
	 }
	 catch (const filesystem_error& ex)
	   {
	     cout << ex.what() << '\n';
	   }

}//exit import folder struct




void Object::importRemoteXml(std::string pathStr){
using namespace std;
cout << "IMPORT REMOTE URL: " << pathStr << endl;

CURL *curl;
  CURLcode res;

  curl = curl_easy_init();

  if(curl) {
      curl_easy_setopt(curl, CURLOPT_URL, pathStr.c_str());
      /* example.com is redirected, so we tell libcurl to follow redirection */
      curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);

      /* Perform the request, res will get the return code */
      res = curl_easy_perform(curl);
      /* Check for errors */
      if(res != CURLE_OK)
        fprintf(stderr, "curl_easy_perform() failed: %s\n",
                curl_easy_strerror(res));

      /* always cleanup */
      curl_easy_cleanup(curl);
    }



}



void Object::importLocalXml(std::string location, bool htmlModeOn){
	using namespace std;
		ifstream o;
		string line;
		string res;
		o.open(location.c_str(), ios::in);
		 if (o.is_open()) {
			 while ( getline(o, line) ){
				 res+=line;
			 }
		 }
		 o.close();

		 if(htmlModeOn){
			 boost::replace_all(res, "<br>", "</br>");
			 boost::replace_all(res, "</br>", "</br>");
		 }

		 cout << res << endl;
		 parseXML(res);
}


} /* namespace stn */



